<template>
    <el-dialog
        v-model="isShow"
        :align-center="true"
        :close-on-click-modal="false"
        :destroy-on-close="true"
        :title="formType === 'add' ? '添加菜单' : '编辑菜单'"
        class="dialog-box"
        @close="onCloseDialog"
    >
        <el-scrollbar max-height="450px">
            <el-form label-width="100" ref="formRef" :model="menuForm" :rules="rules">
                <el-form-item prop="parentId" label="上级菜单">
                    <el-tree-select
                        placeholder="请选择上级菜单"
                        default-expand-all
                        highlight-current
                        :check-on-click-node="true"
                        :expand-on-click-node="false"
                        node-key="id"
                        v-model="menuForm.parentId"
                        :data="parents"
                        ref="selectParentMenuRef"
                        @node-click="onSelectParentMenu"
                        clearable
                    >
                        <template #default="{ data }">
                            <component :is="ParentMenuTag" :data="data"></component>
                        </template>
                        <template #label>
                            <component :is="CurrentParentMenuTag"></component>
                        </template>
                    </el-tree-select>
                </el-form-item>
                <div class="dialog-form-item-group">
                    <el-form-item prop="type" label="类型">
                        <el-radio-group v-model="menuForm.type">
                            <el-radio-button :value="1">目录</el-radio-button>
                            <el-radio-button :value="2">菜单</el-radio-button>
                            <el-radio-button :value="3">按钮</el-radio-button>
                        </el-radio-group>
                    </el-form-item>
                    <el-form-item prop="sort" label="排序">
                        <el-input-number v-model="menuForm.sort" :min="1" />
                    </el-form-item>
                </div>

                <el-form-item prop="name" label="名称">
                    <el-input v-model="menuForm.name" placeholder="请输入菜单名称" clearable></el-input>
                </el-form-item>
                <el-form-item prop="title" label="标题">
                    <el-input v-model="menuForm.title" placeholder="请输入菜单标题" clearable></el-input>
                </el-form-item>
                <el-form-item prop="permission" label="按钮权限字段" v-if="menuForm.type === 3">
                    <el-input v-model="menuForm.permission" placeholder="请输入权限字段" clearable></el-input>
                    <el-text class="form-tip-label" type="warning">主要用于前端按钮鉴权，建议使用：'控制器名称/操作命名'，例如：'menu/add'</el-text>
                </el-form-item>
                <el-form-item prop="path" label="路由地址" v-if="menuForm.type !== 3">
                    <el-input v-model="menuForm.path" placeholder="请输入路由地址" clearable></el-input>
                </el-form-item>
                <el-form-item prop="componentPath" label="组件地址" v-if="menuForm.type !== 3">
                    <el-select filterable placeholder="请选择组件地址" v-model="menuForm.componentPath" clearable>
                        <el-option v-for="(item, index) in componentPathArr" :key="index" :label="item" :value="item"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="接口权限">
                    <el-tree-select
                        v-model="menuForm.apiIds"
                        placeholder="请选择接口权限"
                        :data="apis"
                        node-key="id"
                        show-checkbox
                        default-expand-all
                        render-after-expand
                        clearable
                        multiple
                        filterable
                        collapse-tags
                        collapse-tags-tooltip
                    ></el-tree-select>
                </el-form-item>
                <el-form-item prop="redirect" label="重定向地址" v-if="menuForm.type !== 3">
                    <el-input v-model="menuForm.redirect" placeholder="请输入重定向地址" clearable></el-input>
                </el-form-item>
                <el-form-item prop="description" label="描述">
                    <el-input type="textarea" v-model="menuForm.description" placeholder="请输入菜单描述"></el-input>
                </el-form-item>
                <el-form-item prop="icon" label="图标" v-if="menuForm.type !== 3">
                    <el-input v-model="menuForm.icon" placeholder="请输入图标名称" clearable @clear="onClearIcon">
                        <template #prepend>
                            <el-button v-if="!menuForm.icon" @click="onOpenSelectIconDialog">选择图标</el-button>
                            <Icon v-else :name="menuForm.icon" @click="onOpenSelectIconDialog"></Icon>
                        </template>
                    </el-input>
                </el-form-item>

                <div class="dialog-form-item-group">
                    <el-form-item label="是否启用">
                        <el-switch v-model="menuForm.isEnabled" />
                    </el-form-item>
                    <el-form-item label="是否隐藏">
                        <el-switch v-model="menuForm.isHidden" />
                    </el-form-item>
                    <el-form-item label="是否缓存">
                        <el-switch v-model="menuForm.isKeepalive" />
                    </el-form-item>
                    <el-form-item label="是否固定">
                        <el-switch v-model="menuForm.isAffis" />
                    </el-form-item>
                </div>
            </el-form>
        </el-scrollbar>

        <template #footer>
            <el-button @click="onCancel">取消</el-button>
            <el-button @click="onConfirm" type="primary">确认</el-button>
        </template>
    </el-dialog>
    <IconSelect ref="iconSelectRef" @onSelectIcon="onSelectIcon"></IconSelect>
</template>

<script setup lang="tsx">
import { ApiType } from '@/api/system/api/types'
import { MenuForm, MenuType } from '@/api/auth/menu/types'
import Icon from '@/components/icon/Icon.vue'
import { QueryFormType } from '@/types/queryform'
import { IconNameType } from '@/types/type'
import { getFlatArray, getMenuTagType } from '@/utils/common'
import { FormInstance, FormRules, TagProps } from 'element-plus'
// 是否显示dialog
const isShow = ref(false)
// 表单类型
const formType = ref<FormType>('add')
// 表单实例 Ref
const formRef = ref<FormInstance>()
// 选择图标dialog Ref
const iconSelectRef = ref()
// 选择上级菜单下拉框 Ref
const selectParentMenuRef = ref()
//组件地址数组
const componentPathArr = computed(() => {
    const views = Object.keys(import.meta.glob('@/views/**/*.vue')).filter((item) => !item.includes('Form'))
    const layout = Object.keys(import.meta.glob('@/layout/Layout.vue'))
    return [...views, ...layout]
})
// 表单初始数据
const initform: Partial<MenuForm> = {
    id: undefined,
    parentId: undefined,
    name: '',
    title: '',
    path: '',
    componentPath: '',
    redirect: '',
    permission: '',
    description: '',
    type: 1,
    sort: 0,
    icon: undefined,
    isEnabled: true,
    isHidden: false,
    isKeepalive: false,
    isAffis: false,
    apiIds: [],
}
// 表单数据
const menuForm = reactive<Partial<MenuForm>>({ ...initform })
// 表单校验规则

const rules = reactive<FormRules<MenuForm>>({
    name: [
        {
            type: 'string',
            required: true,
            message: '菜单名称不能为空',
            trigger: 'change',
        },
        {
            pattern: /^[A-Z]+[a-zA-Z]*$/,
            message: '菜单名称必须是大写字母开头',
            trigger: 'change',
        },
    ],
    title: [
        {
            type: 'string',
            required: true,
            message: '菜单标题不能为空',
            trigger: 'change',
        },
    ],
})
const apis = ref<ApiType[]>()
// 可供选择的父节点菜单
const parents = ref<MenuForm[]>()

const emit = defineEmits<{ onTableAction: [action: TableActionType, params: any] }>()

watch(
    () => isShow.value,
    () => {
        if (isShow.value) {
            getData()
        }
    },
)
const getData = async () => {
    await getApis()
    await getParents()
}

const getApis = async () => {
    const result = await getAllApis()
    if (result.isSuccess) {
        apis.value = result.data
    }
}
const getParents = async () => {
    const queryform: QueryFormType<MenuType> = {
        sort: 'sort',
        order: true,
        queryConditions: [
            {
                name: 'type',
                operator: 'NotEqual',
                value: 3,
            },
        ],
    }
    const result = await getAllMenus(queryform)
    if (result.isSuccess) {
        parents.value = result.data
    }
}

// 上级菜单Tag组件类型
interface ParentMenuTagType {
    icon: IconNameType
    title: string
    type?: TagProps['type']
    value?: string
}
// 上级菜单Tag组件
const ParentMenuTag = (data: any) => {
    if (!data) return
    const menu = data.data
    const tag = getMenuTagType(menu.type)
    return MenuTag({ icon: menu.icon, title: menu.title, type: tag?.type, value: tag?.value })
}
// 当前选择的上级菜单Tag组件
const CurrentParentMenuTag = () => {
    if (!menuForm.parentId) return
    if (!parents.value || parents.value.length === 0) return
    const flatArr = getFlatArray(parents.value)
    const menu = flatArr.find((item) => item.id === menuForm.parentId)
    if (!menu) return
    const tag = getMenuTagType(menu.type)
    return MenuTag({ icon: menu.icon, title: menu.title, type: tag?.type, value: tag?.value })
}
// 菜单Tag组件
const MenuTag = (tag: ParentMenuTagType) => {
    return (
        <div style={{ height: '20px', display: 'flex', alignItems: 'center' }}>
            <Icon name={tag.icon}></Icon>
            <span style={{ margin: '0 10px' }}>{tag.title}</span>
            <el-tag type={tag.type}>{tag.value}</el-tag>
        </div>
    )
}

// 选择上级菜单触发
const onSelectParentMenu = (menu: MenuType) => {
    menuForm.parentId = menu.id
    switch (menu.type) {
        case 1:
            menuForm.type = 2
            break
        case 2:
            menuForm.type = 3
            break
        default:
            break
    }
    // 选择节点后，隐藏下拉框
    nextTick(() => {
        if (selectParentMenuRef.value) {
            selectParentMenuRef.value.blur()
        }
    })
}

// 打开选择图标dialog
const onOpenSelectIconDialog = () => iconSelectRef.value.onOpenDialog()
// 选择图标回调
const onSelectIcon = (icon: IconNameType) => (menuForm.icon = icon)
// 清空已选择的图标
const onClearIcon = () => (menuForm.icon = undefined)

// 打开dialog
const onOpenDialog = (action: FormType, row?: MenuForm) => {
    formType.value = action
    if (action !== 'add' && row) {
        if (row.parentId === 0) {
            Object.assign(menuForm, { ...row, parentId: undefined })
        } else {
            Object.assign(menuForm, row)
        }
    }
    isShow.value = true
}
// 关闭dialog
const onCloseDialog = () => {
    isShow.value = false
    Object.assign(menuForm, initform)
}
// 取消
const onCancel = () => onCloseDialog()
// 完成确认
const onConfirm = async () => {
    await formRef.value?.validate()

    if (menuForm.apiIds && menuForm.apiIds.length !== 0 && apis.value && apis.value?.length !== 0) {
        const flatArr = getFlatArray(apis.value)
        flatArr.forEach((item) => {
            if (!item.parentId || item.parentId === 0) {
                return
            }
            if (menuForm.apiIds?.includes(item.id)) {
                const parentArr = getAncestorIds(flatArr, item, false)
                if (parentArr.length !== 0) {
                    menuForm.apiIds.push(...parentArr)
                }
            }
        })
        menuForm.apiIds = [...new Set(menuForm.apiIds)]
    }

    emit('onTableAction', 'addOrEditSubmit', menuForm)
}
defineExpose({
    onOpenDialog,
    onCloseDialog,
})
</script>

<style lang="scss" scoped>
.dialog-form-item-group {
    display: flex;
    justify-content: flex-start;
    align-items: center;
    flex-wrap: wrap;
}
</style>
